package com.smsc.headend.connector.service.asset.impl;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.smsc.headend.common.enums.DeviceType;
import com.smsc.headend.connector.manager.DeviceKeyManager;
import com.smsc.headend.connector.service.FeignAssetManagementService;
import com.smsc.headend.connector.service.TerminalChannelService;
import com.smsc.headend.connector.service.asset.AssetService;
import com.smsc.headend.module.asset.dmo.ComConfigDMO;
import com.smsc.headend.module.asset.dmo.DLMSConfigDMO;
import com.smsc.headend.module.asset.dmo.MeterConfigDMO;
import com.smsc.headend.module.asset.entity.ComEntity;
import com.smsc.headend.module.asset.entity.Dcu;
import com.smsc.headend.module.asset.entity.Meter;

import com.smsc.headend.module.asset.entity.PlcMeterStatus;
import com.smsc.headend.module.data.dto.ClearLocalCacheDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class AssetServiceImpl implements AssetService {
    @Autowired
    FeignAssetManagementService assetManagementService;

    @Autowired
    TerminalChannelService terminalChannelService;

    @Autowired
    DeviceKeyManager deviceKeyManager;

    LoadingCache<String, String> systemParamCache = CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build(new CacheLoader<String, String>() {
        @Override
        public String load(String key) throws Exception {
            return assetManagementService.getPropertyValue(key);
        }
    });

    LoadingCache<Long, Meter> meterLocalCache = CacheBuilder.newBuilder()
            //设置缓存容器的初始容量为10
            .initialCapacity(2000)
            // maximumSize 设置缓存大小
//            .maximumSize(65535)
            //设置并发级别为20，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(15)
            // expireAfterWrite设置写缓存后10分钟过期
//            .expireAfterWrite(10, TimeUnit.MINUTES)
//            .refreshAfterWrite(2, TimeUnit.MINUTES)
            .build(new CacheLoader<Long, Meter>() {
                @Override
                public Meter load(Long meterId) throws Exception {
                    return assetManagementService.getMeterById(meterId);
                }
            });

    LoadingCache<Long, MeterConfigDMO> meterConfigLocalCache = CacheBuilder.newBuilder()
            //设置缓存容器的初始容量为10
            .initialCapacity(2000)
            // maximumSize 设置缓存大小
//            .maximumSize(65535)
            //设置并发级别为20，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(15)
            // expireAfterWrite设置写缓存后10分钟过期
//            .expireAfterWrite(10, TimeUnit.MINUTES)
//            .refreshAfterWrite(2, TimeUnit.MINUTES)
            .build(new CacheLoader<Long, MeterConfigDMO>() {
                @Override
                public MeterConfigDMO load(Long meterId) throws Exception {
                    return assetManagementService.getMeterConfigById(meterId);
                }
            });

    LoadingCache<Long, ComConfigDMO> comConfigDMOLoadingCache = CacheBuilder.newBuilder()
            //设置缓存容器的初始容量为10
            .initialCapacity(2000)
            // maximumSize 设置缓存大小
//            .maximumSize(65535)
            //设置并发级别为20，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(15)
            // expireAfterWrite设置写缓存后10分钟过期
//            .expireAfterWrite(10, TimeUnit.MINUTES)
//            .refreshAfterWrite(2, TimeUnit.MINUTES)
            .build(new CacheLoader<Long, ComConfigDMO>() {
                @Override
                public ComConfigDMO load(Long comId) throws Exception {
                    return assetManagementService.getComConfigById(comId);
                }
            });

    LoadingCache<Long, Dcu> dcuLocalCache = CacheBuilder.newBuilder()
            //设置缓存容器的初始容量为10
            .initialCapacity(200)
            // maximumSize 设置缓存大小
            .maximumSize(65535)
            //设置并发级别为20，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(20)
            // expireAfterWrite设置写缓存后10分钟过期
//            .expireAfterWrite(10, TimeUnit.MINUTES)
//            .refreshAfterWrite(2, TimeUnit.MINUTES)
            .build(new CacheLoader<Long, Dcu>() {
                @Override
                public Dcu load(Long dcuId) throws Exception {
                    return assetManagementService.getDcuById(dcuId);
                }
            });

    LoadingCache<Long, PlcMeterStatus> plcMeterStatusCache = CacheBuilder.newBuilder()
            //设置缓存容器的初始容量为10
            .initialCapacity(2000)
            // maximumSize 设置缓存大小
//            .maximumSize(65535)
            //设置并发级别为20，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(20)
            // expireAfterWrite设置写缓存后10分钟过期
//            .expireAfterWrite(10, TimeUnit.MINUTES)
//            .refreshAfterWrite(2, TimeUnit.MINUTES)
            .build(new CacheLoader<Long, PlcMeterStatus>() {
                @Override
                public PlcMeterStatus load(Long meterId) throws Exception {
                    return assetManagementService.getPlcMeterStatus(meterId);
                }
            });

    @Override
    public String getSystemProperty(String key) {
        try {
            return systemParamCache.get(key);
        } catch (Exception e) {
            log.error("get system param fail", e);
        }
        return null;
    }

    @Override
    public String getDeviceCustomerNo(Long deviceId, Long deviceType) {
        return assetManagementService.getDeviceCustomerSn(deviceType, deviceId);
    }

    @Override
    public String getDeviceMfgSn(Long deviceId, Long deviceType) {
        return assetManagementService.getDeviceMfgSn(deviceType, deviceId);
    }

    @Override
    public Meter getMeterById(Long meterId) {
        try {
            return meterLocalCache.get(meterId);
        } catch (Exception e) {
            log.info("failed to get meter local cache, meterId -> {}", meterId);
        }
        return null;
    }

    public MeterConfigDMO getMeterConfig(Long deviceId) {
        try {
            return meterConfigLocalCache.get(deviceId);
        } catch (Exception e) {
            log.info("failed load meterConfig local cache, meterId -> {}", deviceId);
        }
        return null;
    }

    @Override
    public ComConfigDMO getComConfigById(Long comId) {
        try {
            return comConfigDMOLoadingCache.get(comId);
        } catch (Exception e) {
            log.info("failed load comConfig local cache, meterId -> {}", comId);
        }
        return null;
    }

    @Override
    public Dcu getDcuById(Long dcuId) {
        try {
            return dcuLocalCache.get(dcuId);
        } catch (Exception e) {
            log.info("failed to get dcu local cache, dcuId -> {}", dcuId);
        }
        return null;
    }

    @Override
    public void clearMeterCacheById(Long meterId) {
        meterLocalCache.invalidate(meterId);
        meterConfigLocalCache.invalidate(meterId);
        deviceKeyManager.invalidKey(meterId);
    }

    @Override
    public void clearComEntityCacheById(ClearLocalCacheDto dto) {
        terminalChannelService.clearComEntityCacheById(dto);
    }

    @Override
    public PlcMeterStatus getPlcMeterStatus(Long meterId) {
        try {
            return plcMeterStatusCache.get(meterId);
        } catch (Exception e) {
            log.info("failed to get plcMeterStatusCache local cache, meterId -> {}", meterId);
        }
        return null;
    }

    @Override
    public void clearPlcMeterStatus(Long meterId) {
        plcMeterStatusCache.invalidate(meterId);
    }

    @Override
    public void clearDcuCacheById(Long dcuId) {
        dcuLocalCache.invalidate(dcuId);
    }

    @Override
    public void loadAssetToCache(ComEntity comEntity) {
        if (Optional.ofNullable(comEntity.getComDeviceType()).orElse(0L).longValue() == DeviceType.GPRS.getId().longValue()) {
            this.getMeterById(comEntity.getDeviceId());
            this.getMeterConfig(comEntity.getDeviceId());
        }
    }

}
